Option Explicit On
Option Strict On

Imports System.Collections
Imports System.Collections.Generic
Imports nstl
Imports NUnit.Framework
Imports NStl.SyntaxHelper


Namespace nstl.test
    <TestFixture()> _
    Public Class FunctionalTest

        ''' <summary>
        ''' Initialize() is called once during test execution before
        ''' test methods in this test class are executed.
        ''' </summary>
        <SetUp()> Public Sub Initialize()
            ' TODO: Add test initialization code
        End Sub

        ''' <summary>
        ''' Cleanup() is called once during test execution after
        ''' test methods in this class have executed unless the
        ''' corresponding Initialize() call threw an exception.
        ''' </summary>
        <TearDown()> Public Sub Cleanup()
            ' TODO: Add test cleanup code
        End Sub

        <Test()> _
        Public Sub select1st()
            select1st_imp()
            select1st_dictentry()
        End Sub

        Private Sub select1st_imp()
            Dim sel1st As IUnaryFunction(Of KeyValuePair(Of Integer, Single), Integer) = [Select].FirstFromKeyValuePair(Of Integer, Single)()
            Dim p As New KeyValuePair(Of Integer, Single)(10, 42.0F)

            Assert.AreEqual(10, sel1st.Execute(p))
        End Sub
        Private Sub select1st_dictentry()
            Dim sel1st As IUnaryFunction(Of DictionaryEntry, Integer) = [Select].FirstFromDictionaryEntry(Of Integer)()
            Dim p As New DictionaryEntry(10, 42.0F)

            Assert.AreEqual(10, sel1st.Execute(p))
        End Sub

        <Test()> _
       Public Sub select2nd()
            select2nd_imp()
            select2nd_dictentry()
        End Sub

        Private Sub select2nd_imp()
            Dim sel2nd As IUnaryFunction(Of KeyValuePair(Of Integer, Single), Single) = [Select].SecondFromKeyValuePair(Of Integer, Single)()
            Dim p As New KeyValuePair(Of Integer, Single)(10, 42.0F)

            Assert.AreEqual(42.0F, sel2nd.Execute(p))
        End Sub
        Private Sub select2nd_dictentry()
            Dim sel2nd As IUnaryFunction(Of DictionaryEntry, Single) = [Select].SecondFromDictionaryEntry(Of Single)()
            Dim p As New DictionaryEntry(10, 42.0F)

            Assert.AreEqual(42.0F, sel2nd.Execute(p))
        End Sub

        <Test()> _
        Public Sub not2()
            Dim p As IBinaryPredicate(Of Integer, Integer) = Compare.EqualTo(Of Integer)()

            Assert.IsTrue(p.Execute(10, 10))
            Assert.IsFalse(Logical.Not2(p).Execute(10, 10))
        End Sub
        <Test()> _
        Public Sub not1()
            Dim p As IUnaryPredicate(Of Integer) = Functional.IsDefault(Of Integer)()
            Assert.IsTrue(p.Execute(0))
            Assert.IsFalse(Logical.Not1(p).Execute(0))
        End Sub
        <Test()> _
        Public Sub logical_and()
            Dim andFunc As IBinaryPredicate(Of Boolean, Boolean) = Logical.And()

            Assert.IsTrue(andFunc.Execute(True, True))
            Assert.IsFalse(andFunc.Execute(True, False))
            Assert.IsFalse(andFunc.Execute(False, True))
            Assert.IsFalse(andFunc.Execute(False, False))
        End Sub
        <Test()> _
        Public Sub logical_not()
            Dim notFunc As IUnaryPredicate(Of Boolean) = Logical.Not()

            Assert.IsFalse(notFunc.Execute(True))
            Assert.IsTrue(notFunc.Execute(False))
        End Sub
        <Test()> _
        Public Sub logical_or()
            Dim orFunc As IBinaryPredicate(Of Boolean, Boolean) = Logical.Or()

            Assert.IsTrue(orFunc.Execute(True, True))
            Assert.IsTrue(orFunc.Execute(True, False))
            Assert.IsTrue(orFunc.Execute(False, True))
            Assert.IsFalse(orFunc.Execute(False, False))
        End Sub

        <Test()> _
        Public Sub is_kind_of()
            Dim isKindOf As IBinaryPredicate(Of Type, Type) = Functional.IsKindOf()

            Assert.IsTrue(isKindOf.Execute(GetType(System.ArgumentException), GetType(Exception)))
            Assert.IsTrue(isKindOf.Execute(GetType(System.Collections.ArrayList), GetType(System.Collections.IEnumerable)))
            Assert.IsFalse(isKindOf.Execute(GetType(System.ArgumentException), GetType(System.Collections.ArrayList)))

        End Sub

        <Test()> _
        Public Sub ptr_fun_binary()

            Dim binStaticFunc As IBinaryFunction(Of Integer, Single, Single) = _
                Functional.PtrFun(Of Integer, Single, Single)(AddressOf PtrFunTest.BinaryStaticTestFunc)

            Assert.AreEqual(10.0F, binStaticFunc.Execute(4, 6.0F))

            Dim t As New PtrFunTest
            Dim binFunc As IBinaryFunction(Of Integer, Single, Single) = _
                Functional.PtrFun(Of Integer, Single, Single)(AddressOf t.BinaryTestFunc)

            Assert.AreEqual(16.0F, binFunc.Execute(4, 6.0F))

            'delegate versions
            Dim binaryStaticDelegateFunc As IBinaryFunction(Of Integer, Single, Single) = _
                Functional.PtrFun(Of Integer, Single, Single)(AddressOf PtrFunTest.BinaryStaticTestFunc)
            Assert.AreEqual(10.0F, binaryStaticDelegateFunc.Execute(4, 6.0F))


            Dim binaryInstanceDelegateFunc As IBinaryFunction(Of Integer, Single, Single) = _
                Functional.PtrFun(Of Integer, Single, Single)(AddressOf t.BinaryTestFunc)
            Assert.AreEqual(16.0F, binaryInstanceDelegateFunc.Execute(4, 6.0F))

            Dim binaryInstanceDelegateSub As IBinaryVoidFunction(Of Integer, Single) = _
                Functional.PtrFun(Of Integer, Single)(AddressOf t.BinaryTestSub)
            binaryInstanceDelegateSub.Execute(4, 2.0F)
            Assert.AreEqual(14.0F, t.theFloat)

        End Sub
        Private Class PtrFunTest
            Public Shared Function BinaryStaticTestFunc(ByVal i As Integer, ByVal f As Single) As Single
                Return i + f
            End Function
            Public Function BinaryTestFunc(ByVal i As Integer, ByVal f As Single) As Single
                Return i + 2 * f
            End Function
            Public Sub BinaryTestSub(ByVal i As Integer, ByVal f As Single)
                theFloat = i + 5 * f
            End Sub
            Public theFloat As Single
            Public Shared Function UnaryStaticTestFunc(ByVal i As Integer) As Single
                Return i * 2
            End Function
            Public Function UnaryTestFunc(ByVal i As Integer) As Single
                Return i * 4
            End Function
        End Class
        <Test()> _
        Public Sub ptr_fun_unary()
            'static func
            Dim unaryStaticFunc As IUnaryFunction(Of Integer, Single) = _
                Functional.PtrFun(Of Integer, Single)(AddressOf PtrFunTest.UnaryStaticTestFunc)

            Assert.AreEqual(8.0F, unaryStaticFunc.Execute(4))

            'instance func
            Dim t As New PtrFunTest
            Dim unaryFunc As IUnaryFunction(Of Integer, Single) = _
                Functional.PtrFun(Of Integer, Single)(AddressOf t.UnaryTestFunc)

            Assert.AreEqual(16.0F, unaryFunc.Execute(4))

            'delegate versions
            Dim unaryStaticDelegate As IUnaryFunction(Of Integer, Single) = _
                Functional.PtrFun(Of Integer, Single)(AddressOf PtrFunTest.UnaryStaticTestFunc)
            Assert.AreEqual(8.0F, unaryStaticDelegate.Execute(4))

            Dim unaryInstanceDelegate As IUnaryFunction(Of Integer, Single) = _
                Functional.PtrFun(Of Integer, Single)(AddressOf t.UnaryTestFunc)
            Assert.AreEqual(16.0F, unaryFunc.Execute(4))
        End Sub
        <Test()> _
       Public Sub not_equal_to()
            Dim equ As IBinaryPredicate(Of Integer, Integer) = Compare.NotEqualTo(Of Integer)()

            Assert.IsFalse(equ.Execute(1, 1))
            Assert.IsTrue(equ.Execute(3, 1))
            Assert.IsTrue(equ.Execute(3, 4))
        End Sub
        <Test()> _
        Public Sub equal_to()
            Dim equ As IBinaryPredicate(Of Integer, Integer) = Compare.EqualTo(Of Integer)()

            Assert.IsTrue(equ.Execute(1, 1))
            Assert.IsFalse(equ.Execute(3, 1))
            Assert.IsFalse(equ.Execute(3, 4))
        End Sub
        <Test()> _
        Public Sub less()
            Dim less As IBinaryPredicate(Of Integer, Integer) = Compare.Less(Of Integer)()

            Assert.IsFalse(less.Execute(1, 1))
            Assert.IsFalse(less.Execute(3, 1))
            Assert.IsTrue(less.Execute(3, 4))
        End Sub
        <Test()> _
        Public Sub less_equal()
            Dim less As IBinaryPredicate(Of Integer, Integer) = Compare.LessEqual(Of Integer)()

            Assert.IsTrue(less.Execute(1, 1))
            Assert.IsFalse(less.Execute(3, 1))
            Assert.IsTrue(less.Execute(3, 4))
        End Sub
        <Test()> _
        Public Sub greater()
            Dim greater As IBinaryPredicate(Of Integer, Integer) = Compare.Greater(Of Integer)()

            Assert.IsFalse(greater.Execute(1, 1))
            Assert.IsTrue(greater.Execute(3, 1))
            Assert.IsFalse(greater.Execute(3, 4))
        End Sub
        <Test()> _
        Public Sub greater_equal()
            Dim greater As IBinaryPredicate(Of Integer, Integer) = Compare.GreaterEqual(Of Integer)()

            Assert.IsTrue(greater.Execute(1, 1))
            Assert.IsTrue(greater.Execute(3, 1))
            Assert.IsFalse(greater.Execute(3, 4))
        End Sub

        <Test()> _
            Public Sub bind1st()
            Dim binder As IUnaryFunction(Of Integer, Boolean) = Bind.First(Compare.Less(Of Integer)(), 4)
            Assert.IsTrue(binder.Execute(5))
        End Sub
        <Test()> _
            Public Sub bind2nd()
            Dim binder As IUnaryFunction(Of Integer, Boolean) = Bind.Second(Compare.Less(Of Integer)(), 4)
            Assert.IsTrue(binder.Execute(3))
        End Sub
        <Test()> _
        Public Sub compose_fg()
            Dim nullary As INullaryFunction(Of Integer) = New IntGenerator10
            Dim unary As IUnaryFunction(Of Integer, Single) = New int2single

            Dim comp As INullaryFunction(Of Single) = Compose.FG(unary, nullary)

            Dim test As Single = comp.Execute()
            Assert.AreEqual(test, 10.0F)
        End Sub
        <Test()> _
        Public Sub ComposeFGx()
            Dim g As IUnaryFunction(Of Integer, Integer) = Bind.Second(New MultiplyInt(), 5)
            Dim f As IUnaryFunction(Of Integer, Single) = New int2single()

            Dim comp As IUnaryFunction(Of Integer, Single) = Compose.FGx(f, g)

            Dim test As Single = comp.Execute(5)
            Assert.AreEqual(test, 25.0F)
        End Sub
        <Test()> _
        Public Sub compose_fgxhx()
            Dim g As IUnaryFunction(Of Integer, Single) = New int2single()
            Dim h As IUnaryFunction(Of Integer, Integer) = Project.Identity(Of Integer)()
            Dim f As IBinaryFunction(Of Single, Integer, Single) = New MultiplySingleAndInt

            Dim comp As IUnaryFunction(Of Integer, Single) = Compose.FGxHx(f, g, h)

            Dim test As Single = comp.Execute(5)
            Assert.AreEqual(test, 25.0F)
        End Sub
        <Test()> _
        Public Sub compose_fgxy()
            Dim g As IBinaryFunction(Of Integer, Single, Single) = New MultiplyIntSingle
            Dim f As IUnaryFunction(Of Single, Single) = Bind.First(New MultiplyIntSingle, 5)

            Dim comp As IBinaryFunction(Of Integer, Single, Single) = Compose.FGxy(f, g)

            Dim test As Single = comp.Execute(5, 6.0F)
            Assert.AreEqual(test, 150.0F)
        End Sub
        <Test()> _
        Public Sub compose_fgxhy()
            Dim f As IBinaryFunction(Of Single, Integer, Single) = New MultiplySingleAndInt
            Dim g As IUnaryFunction(Of Single, Single) = Bind.First(New MultiplyIntSingle, 10)
            Dim h As IUnaryFunction(Of Integer, Integer) = Bind.Second(New MultiplyInt, 5)

            Dim comp As IBinaryFunction(Of Single, Integer, Single) = Compose.FGxHy(f, g, h)

            Dim test As Single = comp.Execute(3.0F, 5)
            Assert.AreEqual(750.0F, test)
        End Sub
    End Class
End Namespace


